﻿#if NETFX_CORE && !WinRT
#	define WinRT
#endif

using System;
using System.Linq.Expressions;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace DailyFx.UI 
{

    /// <summary>
    ///		Extends <see cref = "INotifyPropertyChanged" /> such that the change event can be raised by external parties.
    /// </summary>
    public interface INotifyPropertyChangedEx : INotifyPropertyChanged
	{
        /// <summary>
        ///		Raises to notify subscribers of the property changed.
        /// </summary>
        void RaisePropertyChanged ( string propertyName );

    }

    /// <summary>
    ///   A base class that implements the infrastructure for property changed notification 
	///   and automatically performs UI thread marshalling.
    /// </summary>
#if !SILVERLIGHT && !WinRT
    // [Serializable]
#endif
    public class NotifyPropertyChanged : INotifyPropertyChangedEx 
	{

        /// <summary>
        ///   Occurs when a property value changes.
        /// </summary>
#if !SILVERLIGHT && !WinRT
        // [field: NonSerialized]
#endif
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

#if !SILVERLIGHT && !WinRT
       // [field: NonSerialized]
#endif
        bool isNotifying = true; // serializator try to serialize even autogenerated fields


        /// <summary>
        ///   Enables/Disables property change notification.
        /// </summary>
#if !WinRT
        [Browsable(false)]
#endif
        public bool IsNotifying 
		{
            get { return isNotifying; }
            set { isNotifying = value; }
        }

       
        /// <summary>
        ///   Raises to notify subscribers of the property changed.
        /// </summary>
#if WinRT || NET45
        public virtual void RaisePropertyChanged( [CallerMemberName]string propertyName = "" ) 
		{
#else
        public virtual void RaisePropertyChanged ( string propertyName ) 
		{
#endif
			if ( IsNotifying )
			{
                Execution.OnUIThread( () => OnPropertyChanged( new PropertyChangedEventArgs(propertyName)) );
            }
        }

      
        /// <summary>
        ///   Raises the <see cref="E:PropertyChanged" /> event directly.
        /// </summary>
        [EditorBrowsable(EditorBrowsableState.Never)]
        protected void OnPropertyChanged ( PropertyChangedEventArgs e ) 
		{
            if ( this.PropertyChanged != null) 
			{
                 this.PropertyChanged ( this, e );
            }
        }

    }


	
	public static class INotifyPropertyChangedExtension
	{
		/// <summary>
		///     Notifies subscribers of the property(lambda expression) been changed .
		/// </summary>
		public static void RaisePropertyChanged<TProperty> ( this INotifyPropertyChangedEx target, Expression<Func<TProperty>> expression )
		{ 
			var lambda = expression as LambdaExpression;
			MemberExpression memberExpression;
			if (lambda.Body is UnaryExpression)
			{
				var unaryExpression = lambda.Body as UnaryExpression;
				memberExpression = unaryExpression.Operand as MemberExpression;
			}
			else
			{
				memberExpression = lambda.Body as MemberExpression;
			}
			if (memberExpression != null)
			{
				var propertyInfo = memberExpression.Member as System.Reflection.PropertyInfo;
				if (propertyInfo != null)
					target.RaisePropertyChanged( propertyInfo.Name );
			}
		}
	}

   
}
